// Chrometris 1.0 for Chrome OS
// Copyright (c) 2010 Joseph Huckaby

Sprite.extend( 'Player', {
	
	width: 40 * 4,
	height: 40 * 4,
	
	tx: 0,
	ty: 0,
	
	rotate_map: [
		[ [3,0], [3,1], [3,2], [3,3] ],
		[ [2,0], [2,1], [2,2], [2,3] ],
		[ [1,0], [1,1], [1,2], [1,3] ],
		[ [0,0], [0,1], [0,2], [0,3] ]
	],
	
	init: function() {
		this.__parent.init.call(this);
	},
	
	gameOver: function() {
		// alert("GAME OVER");
		Game.stop();
		$A.quiet();
		$A.playSound( 'game_over' );
		
		var html = '';
		html += '<div id="game_over">Game Over</div>';
		html += '<div class="dialog_links"><a href="javascript:void($C.titleScreen())">Return to Title</a></div>';
		$C.showDialog( html );
		
		// $C.titleScreen();
	},
	
	setupNewPiece: function(piece_idx) {
		var piece = Chrometris.pieces[piece_idx];
		var color = Chrometris.colors[piece_idx];
		
		this.piece = piece;
		this.color = color;
		
		this.map = [];
		
		for (var x = 0; x < 4; x++) {
			var col = this.map[x] = [];
			for (var y = 0; y < 4; y++) {
				col[y] = piece[x][y];
			}
		}
		
		this.tx = 2;
		this.ty = -2;
		
		this.constrainBounds();
		this.renderMap();
		
		if (this.checkCollision()) {
			// collision on spawn = game over
			this.gameOver();
		}
	},
	
	renderMap: function() {
		// render our 16 tiles into HTML
		var html = '';
		
		for (var y = 0; y < 4; y++) {
			for (var x = 0; x < 4; x++) {
				var ch = this.map[x][y];
				html += ch ? ('<div class="tile player_'+this.color+'" style="float:left;"></div>') : '<div class="tile_empty_float"></div>';
			}
		}
		
		html += '<div class="clear"></div>';
		this.div.innerHTML = html;
	},
	
	rotate: function() {
		// rotate our map by 90 degrees, and re-render
		var old_map = this.map;
		this.map = [];
		
		for (var x = 0; x < 4; x++) {
			var col = this.map[x] = [];
			for (var y = 0; y < 4; y++) {
				var rot_coords = this.rotate_map[x][y];
				col[y] = old_map[ rot_coords[1] ][ rot_coords[0] ];
			}
		}
		
		if (this.checkCollision()) {
			// do not allow rotation if it causes a collision
			this.map = old_map;
			// $A.playSound('blocked');
			return;
		}
		
		this.constrainBounds();
		this.draw();
		
		this.renderMap();
		
		// $A.playSound('rotate');
	},
	
	checkCollision: function() {
		// check if any of our tiles collide with map tiles
		for (var y = 0; y < 4; y++) {
			for (var x = 0; x < 4; x++) {
				if (this.map[x][y]) {
					if (this.plane.lookupTile( this.tx + x, this.ty + y )) return true;
				}
			}
		}
		return false;
	},
	
	constrainBounds: function() {
		// keep us in the play field, but be smart about our shape
		var moved = false;
		for (var y = 0; y < 4; y++) {
			for (var x = 0; x < 4; x++) {
				if (this.map[x][y]) {
					while (this.tx + x >= this.plane.cols) { this.tx--; moved = true; }
					while (this.tx + x < 0) { this.tx++; moved = true; }
					while (this.ty + y < 0) { this.ty++; moved = true; }
				}
			}
		}
		return moved;
	},
	
	checkBottom: function() {
		// return true if tile is off bottom of playfield, false otherwise
		for (var y = 0; y < 4; y++) {
			for (var x = 0; x < 4; x++) {
				if (this.map[x][y]) {
					if (this.ty + y >= this.plane.rows) return true;
				}
			}
		}
		return false;
	},
	
	cement: function() {
		// cement current map into playfield, and grab next piece
		for (var y = 0; y < 4; y++) {
			for (var x = 0; x < 4; x++) {
				if (this.map[x][y]) {
					this.plane.map[ this.tx + x ][ this.ty + y ] = 1;
					var tile = new Tile();
					tile.className = 'tile ' + this.color;
					tile.tx = this.tx + x;
					tile.ty = this.ty + y;
					tile.id = 'tile_' + tile.tx + '_' + tile.ty;
					this.plane.addSprite( tile );
				}
			}
		}
		
		// check for complete lines
		var line = false;
		for (var y = 0; y < this.plane.rows; y++) {
			var count = 0;
			for (var x = 0; x < this.plane.cols; x++) {
				if (this.plane.map[x][y]) count++;
			}
			if (count == this.plane.cols) {
				// line achieved!
				for (var x = 0; x < this.plane.cols; x++) {
					var tile = this.plane.get( 'tile_' + x + '_' + y );
					tile.destroy();
				}
				
				// move applicable tiles down
				for (var ty = y; ty >= 1; ty--) {
					for (var tx = 0; tx < this.plane.cols; tx++) {
						this.plane.map[tx][ty] = this.plane.map[tx][ty-1];
						if (this.plane.map[tx][ty-1]) {
							var tile = this.plane.get( 'tile_' + tx + '_' + Math.floor(ty-1) );
							tile.ty++;
							tile.rename( 'tile_' + tx + '_' + ty );
						}
					}
				}
				
				// clear top line
				for (var tx = 0; tx < this.plane.cols; tx++) {
					this.plane.map[tx][0] = 0;
				}
				
				$C.lines++;
				line = true;
				
				$C.frameMod--;
				if ($C.frameMod < 1) $C.frameMod = 1;
				
				y = -1;
			} // line achieved
		}
		
		// grab next piece
		this.setupNewPiece( $C.nextPiece );
		$C.nextPiece = $C.getRandPieceIdx();
		
		$C.updateDisp();
		
		$A.playSound( line ? 'line' : 'drop' );
	},
	
	moveRight: function() {
		// move player right by one tile, check for collisions
		this.tx++;
		if (this.checkCollision()) {
			// $A.playSound('blocked');
			this.tx--;
			return;
		}
		if (this.constrainBounds()) {
			// $A.playSound('blocked');
		}
	},
	
	moveLeft: function() {
		// move player left by one tile, check for collisions
		this.tx--;
		if (this.checkCollision()) {
			// $A.playSound('blocked');
			this.tx++;
			return;
		}
		if (this.constrainBounds()) {
			// $A.playSound('blocked');
		}
	},
	
	moveDown: function() {
		// move tile down, and check for cement
		this.ty++;
		if (this.checkCollision() || this.checkBottom()) {
			// hit tile or bottom of playfield, seal tile and create new
			this.ty--;
			this.cement();
		}
	},
	
	handleKeyDown: function(code, e) {
		// a key was pressed
		switch (code) {
			case Game.RIGHT_ARROW: this.moveRight(); break;
			case Game.LEFT_ARROW: this.moveLeft(); break;
			case Game.UP_ARROW: this.rotate(); break;
		}
	},
	
	logic: function() {
		// logic loop
		if (Game.logicClock % $C.frameMod == 0) {
			// time to move tile downward
			this.moveDown();
		}
		
		if ((Game.isKeyDown(Game.DOWN_ARROW) || Game.isKeyDown(Game.SPACE_BAR)) && (Game.logicClock % 4 == 0)) {
			this.moveDown();
		}
	},
	
	draw: function() {
		// update position on screen
		this.x = this.tx * 40;
		this.y = this.ty * 40;
		this.__parent.draw.call(this);
	}
	
} );
